#include "rtc_task.h"
#include "my_api.h"
#include "trans_packer.h"
#include "trans_task.h"
#include "devices.h"
#include "mems.h"
#include "eeprom.h"

typedef struct
{
    uint8_t is_user : 2;
    uint8_t is_sys : 1;
    uint8_t refresh : 1;
} alarm_type_t;

enum
{
    alarm_user_clr,
    alarm_user_wake,
    alarm_user_wake_esp,
};

static alarm_type_t alarm_type = { // 状态指示
    .is_sys = 0,
    .is_user = alarm_user_clr,
    .refresh = 1};
static alarm_type_t alarm_type_save = {
    // 设定，唤醒时会取出此值到alarm_type
    .is_sys = 0,
    .is_user = alarm_user_clr,
};

static void RtcCycCb(void) // 周期回调函数
{
    Rtc_ClrIrqStatus(RtcPrdf);
    alarm_type.refresh = 1;
}

static void RtcAlarmCb(void) // 闹钟回调函数
{
    Rtc_ClrIrqStatus(RtcAlmf);
    alarm_type = alarm_type_save;
    alarm_type_save.is_sys = 0;
    alarm_type_save.is_user = alarm_user_clr;
    alarm_type.refresh = 1;
    sys_set_wake_type(wake_by_alarm);
}

static void power_off_cb(void *value, size_t lenth)
{
    alarm_type.is_sys = 0;
    alarm_type.is_user = alarm_user_clr;
    alarm_type.refresh = 0;
};

/**
 * @brief 获取距离时间最近的闹钟
 *
 * @param time 当前时间
 * @return alarm_paras_t*
 */
static alarm_paras_t *alarm_get_nearly(stc_rtc_time_t *time)
{
    alarm_paras_t *all_alarm = eeprom_get_alarm_paras();
    alarm_paras_t *airly = NULL;
    uint8_t mask = 1 << time->u8DayOfWeek;
    uint16_t tmp_cnt = 23 * 60 + 59;
    uint16_t now_cnt = time->u8Hour * 60 + time->u8Minute;
    for (size_t j = 0; j < 7; j++)
    {
        for (size_t i = 0; i < 30; i++)
        {
            if (all_alarm[i].en_flg == 0)
                continue;
            if ((all_alarm[i].week_flg & mask) == 0)
                continue;
            uint16_t time_alarm_cnt = all_alarm[i].hour * 60 + all_alarm[i].min;
            if (time_alarm_cnt <= now_cnt)
                continue;
            if (time_alarm_cnt >= tmp_cnt)
                continue;

            tmp_cnt = time_alarm_cnt;
            airly = &all_alarm[i];
        }
        if (airly != NULL)
            return airly;
        mask <<= 1;
        if (mask == 0x80)
            mask = 0x01;
    }
    return airly;
}

// /**
//  * @brief 获取从今天起的最近的一次闹钟的周数
//  *
//  * @param week_mask 闹钟一周要响铃的天数的mask标志
//  * @param time 当前日期
//  * @return uint8_t 今天起往后最近的一天的周几（0-6），0xff：错误
//  */
// static uint8_t alarm_get_nearly_week(uint8_t week_mask, stc_rtc_time_t *time)
// {
//     uint8_t tmp = time->u8DayOfWeek;
//     for (size_t i = 0; i < 7; i++)
//     {
//         if ((week_mask & (1 << tmp)))
//             return tmp;
//         tmp++;
//         if (tmp == 7)
//             tmp = 0;
//     }
//     return 0xff;
// }

void rtc_upload_time()
{
    stc_rtc_time_t time;
    Rtc_ReadDateTime(&time);
    uint8_t time_tmp[7] = {time.u8Year, time.u8Month, time.u8Day, time.u8DayOfWeek, time.u8Hour, time.u8Minute, time.u8Second};
    for (size_t i = 0; i < sizeof(time_tmp); i++)
        time_tmp[i] = Change_DateTimeFormat(time_tmp[i]);
    trans_packer_send_pack(esp_trans_get_handle(), "time", time_tmp, sizeof(time_tmp));
}

void rtc_task_init(stc_rtc_time_t *time)
{

#if 1
    stc_rtc_config_t stcRtcConfig;
    stc_rtc_irq_cb_t stcIrqCb;
    stc_rtc_time_t stcTime;
    stc_rtc_alarmset_t stcAlarm;
    stc_rtc_cyc_sel_t stcCycSel;

    DDL_ZERO_STRUCT(stcRtcConfig);
    DDL_ZERO_STRUCT(stcIrqCb);
    DDL_ZERO_STRUCT(stcAlarm);
    DDL_ZERO_STRUCT(stcTime);

    Clk_Enable(ClkXTL, TRUE); // 开启外部晶振32.768

    Clk_SetPeripheralGate(ClkPeripheralRtc, TRUE); // 使能rtc时钟

    stcRtcConfig.enClkSel = RtcClk32768; // 外部32.768
    stcRtcConfig.enAmpmSel = Rtc24h;     // Rtc12h;

    stcTime = *time;

    stcTime.u8DayOfWeek = Rtc_CalWeek(&stcTime.u8Day);
    stcRtcConfig.pstcTimeDate = &stcTime; // 初始化时间参数

    stcIrqCb.pfnAlarmIrqCb = RtcAlarmCb;
    stcIrqCb.pfnTimerIrqCb = RtcCycCb;
    stcRtcConfig.pstcIrqCb = &stcIrqCb; // 初始化回调函数

    stcCycSel.enCyc_sel = RtcPrads;       // 周期类型
    stcCycSel.enPrds_sel = Rtc_None;      // 1min中断一次
    stcRtcConfig.pstcCycSel = &stcCycSel; // 初始化周期中断

    stcRtcConfig.bTouchNvic = TRUE; // 中断使能

    Rtc_DisableFunc(RtcCount); // 关闭计数
    Rtc_Init(&stcRtcConfig);   // 初始化RTC
#if 0
    Gpio_SetFunc_RTC1HZ_P03();
    Clk_SetRTCAdjustClkFreq(CLK_XTH_VAL); // 以高速Pclk来进行补偿,此处要根据具体PCLK时钟源确定
    Rtc_Set1HzMode(1);                    // 0普通模式，1高精度模式
    Rtc_EnableFunc(Rtc1HzOutEn);
    Rtc_SetCompCr(0x0ff); // 此处补偿值要根据实际1hz误差偏差大小来设置，此处只是举例说明
    Rtc_EnableFunc(Rtc_ComenEn);
#endif
    Rtc_EnableFunc(RtcCount); // 开启计数

    alarm_type.refresh = 1;

    // Rtc_EnableFunc(RtcAlarmEn); // 使能闹钟

    key_value_register(NULL, "power_off", power_off_cb);

#endif
}

void rtc_alarm_refresh()
{
    alarm_type.refresh = 1;
}

void rtc_alarm_task()
{
    if (alarm_type.is_user == alarm_user_wake)
    {
        alarm_paras_t *a_tmp = eeprom_get_alarm_setting();
        alarm_paras_t *a_all = eeprom_get_alarm_paras();

        if (a_tmp->del_flg) // 响铃后删除
        {
            a_all[a_tmp->id].en_flg = 0;
        }
        else if (a_tmp->once_flg) // 只响铃一次
        {
            a_all[a_tmp->id].week_flg = 0;
        }

        if (sys_chek_low_soc() == 1)
        {
            sys_power_off();
            return;
        }
        alarm_type.is_user = alarm_user_wake_esp;
        sys_wake_esp_up();
    }
    if (sys_get_esp_wake_sta() && alarm_type.is_user == alarm_user_wake_esp)
    {
        alarm_type.is_user = alarm_user_clr;
        trans_packer_send_pack(esp_trans_get_handle(), "alarming", NULL, 0);
    }

    if (alarm_type.is_sys == 1)
    {
        if (sys_chek_low_soc() == 1)
        {
            sys_power_off();
            return;
        }
        alarm_type.is_sys = 0;
        mems_save_setp();
    }

    if (alarm_type.refresh == 0)
        return;
    alarm_type.refresh = 0;

    stc_rtc_time_t time;
    Rtc_ReadDateTime(&time); // now time

    static uint8_t fff = 1;

    if (fff)
    {
        fff = 0;
        alarm_paras_t *alarm = eeprom_get_alarm_paras();

        alarm[0].en_flg = 1;
        alarm[0].week_flg |= 1 << 5;
        alarm[0].hour = 0x12;
        alarm[0].min = 0x35;
        alarm[0].del_flg = 1;

        alarm[1].en_flg = 1;
        alarm[1].week_flg |= 1 << 5;
        alarm[1].hour = 0x12;
        alarm[1].min = 0x36;
        alarm[1].once_flg = 1;

        alarm[2].en_flg = 1;
        alarm[2].week_flg |= 1 << 5;
        alarm[2].hour = 0x12;
        alarm[2].min = 0x37;

        alarm[3].en_flg = 1;
        alarm[3].week_flg |= 1 << 5;
        alarm[3].hour = 0x12;
        alarm[3].min = 0x38;
    }

    alarm_paras_t *first = alarm_get_nearly(&time);
    if (first == NULL) // 没有闹钟
    {
        Rtc_EnAlarmIrq(Rtc_AlarmInt_Enable); // 关闭闹钟中断
        Rtc_DisableFunc(RtcAlarmEn);
        return;
    }

    stc_rtc_alarmset_t a_tmp = {
        .u8Hour = first->hour,
        .u8Minute = first->min,
        .u8Week = first->week_flg};

    eeprom_set_alarm_setting(first);
    Rtc_DisableFunc(RtcAlarmEn);
    Rtc_EnAlarmIrq(Rtc_AlarmInt_Enable);
    Rtc_SetAlarmTime(&a_tmp);
    Rtc_EnableFunc(RtcAlarmEn);

    alarm_type_save.is_user = alarm_user_wake;

    // printf("time %x-%x-%x %x %x-%x-%x\n", time.u8Year, time.u8Month, time.u8Day, time.u8DayOfWeek, time.u8Hour, time.u8Minute, time.u8Second);

    // printf("now:%d,id:%d,week:%x,hour:%x,min:%x\n", time.u8DayOfWeek, first->id, first->week_flg, first->hour, first->min);

    sys_deep_sleep_start();
}
